// ThreadPoolV4.hpp
// 此版本的线程池是使用的是自己写的Thread对象,同时增加了自己写的锁的封装，来实现RAII;同时增加单例模式
#pragma once
#include <iostream>
#include <unistd.h>
#include <string>
#include <pthread.h>
#include <vector>
#include <queue>
#include "Task.hpp"
#include "Thread.hpp"
#include "Lock.hpp"
using namespace std;
#define SIZE 5
template <class T>
class ThreadPool
{  
private:
    ThreadPool(int size = SIZE)
        : // 这里不用把线程池空间先开好，不然会出现没有默认构造函数问题
          _capacity(size)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ThreadPool(const ThreadPool&)=delete;
    ThreadPool& operator=(const ThreadPool&)=delete;
    //上述的操作保证只能通过GetInstance来创建对象->单例模式
public:
    static ThreadPool<T>* GetInstance()
    {
        if(_ptr==nullptr)//加上来减少锁的一个消耗
        {
        Lock_Guard m(&_instance_mutex);
        if(_ptr==nullptr)
        {
            _ptr=new ThreadPool<T>;
            return _ptr;
        }
        }
        return _ptr;
    }

    ~ThreadPool()
    {
        for (int i = 0; i < _capacity; i++)
        {
            _pool[i].Join();
        }
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    void Init() // 进行一个初始化，把我们的一个Thread对象放进线程池
    {
        for (int i = 0; i < _capacity; i++)
        {
            _pool.push_back(Thread(i, Routine, this));
        }
    }

    void Start() // 我们的线程真正开始执行起来
    {
        for (int i = 0; i < _capacity; i++)
        {
            _pool[i].Run(); // 调用Thread对象的Run函数
        }
    }

    void push(const T &task)
    {
        Lock_Guard m(&_mutex);//使用RAII
        // pthread_mutex_lock(&_mutex);
        _task.push(task);
        pthread_cond_signal(&_cond); // 唤醒线程来执行task
        // pthread_mutex_unlock(&_mutex);
    }

    static void *Routine(void *arg)
    {
        ThreadPool *tp = static_cast<ThreadPool *>(arg);
        while (1)
        {
             T t;
            // 所有的线程都在这里面运行，省去了创建和销毁的开销
            {
                Lock_Guard m(&tp->_mutex);//通过加上括号来实现RAII
                // pthread_mutex_lock(&tp->_mutex);
                while (tp->_task.empty()) // 使用while而不是if可以更安全，即使意外唤醒了
                {
                    pthread_cond_wait(&tp->_cond, &tp->_mutex);
                }
                t = tp->_task.front(); // 获取任务
                tp->_task.pop();
            }
            // pthread_mutex_unlock(&tp->_mutex);
            t(); // 完成任务
            cout << t.to_customer() << endl;
        }
    }

    void Check()
    {
        for (int i = 0; i < _capacity; i++)
        {
            cout << _pool[i].ThreadName() << endl;
        }
    }

private:
    vector<Thread> _pool;   // 线程池
    queue<T> _task;         // 任务
    int _capacity;          // 线程池的大小
    pthread_mutex_t _mutex; // 保护task的资源
    pthread_cond_t _cond;   // 在没有task时进行一个等待
    static pthread_mutex_t _instance_mutex;//单例模式中使用
    static ThreadPool<T>* _ptr;//单例模式中用到的唯一一个对象
};
template<class T>
ThreadPool<T>* ThreadPool<T>::_ptr=nullptr;
template<class T>
pthread_mutex_t ThreadPool<T>::_instance_mutex=PTHREAD_MUTEX_INITIALIZER;